package org.appspot.apprtc;

import android.app.Activity;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.os.Message;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import org.appspot.apprtc.util.LooperExecutor;
import org.json.JSONException;
import org.json.JSONObject;
import org.webrtc.DataChannel;
import org.webrtc.IceCandidate;
import org.webrtc.MediaConstraints;
import org.webrtc.MediaStream;
import org.webrtc.PeerConnection;
import org.webrtc.PeerConnectionFactory;
import org.webrtc.SdpObserver;
import org.webrtc.SessionDescription;
import org.webrtc.VideoCapturerAndroid;
import org.webrtc.VideoRenderer;
import org.webrtc.VideoRendererGui;
import org.webrtc.VideoSource;
import org.webrtc.VideoTrack;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.logging.Handler;
import java.util.logging.LogRecord;

public class TestAcTivity extends Activity implements PeerConnection.Observer {
    private static String TAG = "TESTAcTIVITY";

    // Local preview screen position before call is connected.
    private static final int LOCAL_X_CONNECTING = 50;
    private static final int LOCAL_Y_CONNECTING = 50;
    private static final int LOCAL_WIDTH_CONNECTING = 50;
    private static final int LOCAL_HEIGHT_CONNECTING = 50;
    // Remote video screen position
    private static final int REMOTE_X = 0;
    private static final int REMOTE_Y = 0;
    private static final int REMOTE_WIDTH = 100;
    private static final int REMOTE_HEIGHT = 100;

    private VideoRendererGui.ScalingType scalingType = VideoRendererGui.ScalingType.SCALE_ASPECT_FILL;



    private PeerConnectionFactory peerConnectionFactory;


    public static final String VIDEO_TRACK_ID = "ARDAMSv0";

    private VideoRenderer.Callbacks localRender;

    private VideoRenderer.Callbacks remoteRender;


    private LinkedList<PeerConnection.IceServer> iceServers = new LinkedList<>();


    private static OutputStream outputStream;

    private PeerConnection peerConnection;

    private LooperExecutor executor = new LooperExecutor();

    private byte[] messageCode = {0x11, 0x17, 0x18, 0x19};


    private EditText fromEdit;
    private EditText toEdit;
    private Button upButton;
    private Button callButton;

    private MediaConstraints videoConstraints;

    private String fromWho;

    android.os.Handler handler = new android.os.Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 1:
                    SHOW(TestAcTivity.this, "收到call");
                    break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_ac_tivity);

        GLSurfaceView videoView = (GLSurfaceView) findViewById(R.id.glview_calll);

        VideoRendererGui.setView(videoView, new Runnable() {
            @Override
            public void run() {

            }
        });

        executor.requestStart();

        fromEdit = (EditText) findViewById(R.id.from);
        toEdit = (EditText) findViewById(R.id.to);
        upButton = (Button) findViewById(R.id.uplogin);
        callButton = (Button) findViewById(R.id.call);


        localRender = VideoRendererGui.create(
                LOCAL_X_CONNECTING, LOCAL_Y_CONNECTING,
                LOCAL_WIDTH_CONNECTING, LOCAL_HEIGHT_CONNECTING, scalingType, true);

        remoteRender = VideoRendererGui.create(
                REMOTE_X, REMOTE_Y,
                REMOTE_WIDTH, REMOTE_HEIGHT, scalingType, false);


        PeerConnectionFactory.initializeFieldTrials("WebRTC-SupportVP9/Enabled/");
        PeerConnectionFactory.initializeAndroidGlobals(TestAcTivity.this, true, true,
                true, VideoRendererGui.getEGLContext());
        peerConnectionFactory = new PeerConnectionFactory();

        VideoCapturerAndroid videoCapturerAndroid = VideoCapturerAndroid.create(VideoCapturerAndroid.getNameOfFrontFacingDevice());
        VideoSource videoSource = peerConnectionFactory.createVideoSource(videoCapturerAndroid, new MediaConstraints());


        VideoTrack localVideoTrack = peerConnectionFactory.createVideoTrack(VIDEO_TRACK_ID, videoSource);
        localVideoTrack.addRenderer(new VideoRenderer(localRender));
        MediaStream mediaStream = peerConnectionFactory.createLocalMediaStream("ARDAMS");
        mediaStream.addTrack(localVideoTrack);


        iceServers.add(new PeerConnection.IceServer("stun:test.kc-motor.com"));
        iceServers.add(new PeerConnection.IceServer("turn:test.kc-motor.com", "toto", "password"));


        MediaConstraints pcConstraints = new MediaConstraints();
        pcConstraints.optional.add(
                new MediaConstraints.KeyValuePair("RtpDataChannels", "true"));
        peerConnection = peerConnectionFactory.createPeerConnection(iceServers, pcConstraints, TestAcTivity.this);
        peerConnection.addStream(mediaStream);


        videoConstraints = new MediaConstraints();
        videoConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveVideo", "true"));
        videoConstraints.mandatory.add(new MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"));


        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {

                    ByteArrayOutputStream outStream = new ByteArrayOutputStream();
                    String host = "120.26.69.176";
                    //  String host="192.168.1.113";
                    int port = 8002;
                    Socket client = new Socket(host, port);
                    outputStream = client.getOutputStream();

                    int count = -1;
                    byte[] bytes = new byte[1024];
                    InputStream inputStream = client.getInputStream();


                    while ((count = inputStream.read(bytes, 0, 1024)) != -1) {
                        for (int i = 0; i < count; i++) {
                            outStream.write(bytes[i]);
                            if (bytes[i] == '#' & bytes[count - 1] == '#') {
                                //正常没有粘包，没有半包
                                receiveMessage(outStream);
                                outStream.reset();
                            } else if (bytes[i] == '#') {
                                //有粘包
                                receiveMessage(outStream);
                                outStream.reset();

                            } else {
                                //有半包对于outStream不做处理,让它的数据继续累计

                            }
                        }


                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });

        thread.start();


        upButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendssid(fromEdit.getText().toString());
            }
        });


        callButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                peerConnection.createOffer(new MySdpServer(), videoConstraints);
            }
        });


    }


    private void receiveMessage(ByteArrayOutputStream outStream) {
        String s = new String(outStream.toByteArray()).trim();
        System.out.println("来自服务器端" + s);
        System.out.println("来自服务器端字节" + Arrays.toString(outStream.toByteArray()));
        Message message = new Message();
        message.what = 1;
        handler.sendMessage(message);

        byte[] result = outStream.toByteArray();

        byte messageCode = result[0];

        byte[] content = new byte[result.length - 2];
        System.arraycopy(result, 1, content, 0, content.length);
        switch (messageCode) {
            case 0x17:
                if (content.length > 5) {
                    byte[] from = new byte[16];
                    System.arraycopy(content, 0, from, 0, from.length);
                    fromWho = new String(from);
                    Log.i(TAG, "来自谁" + fromWho);
                    byte[] jsonByte = new byte[content.length - 16];
                    System.arraycopy(content, 16, jsonByte, 0, jsonByte.length);
                    Log.i(TAG, "收到的json" + new String(jsonByte));
                    try {
                        JSONObject callJson = new JSONObject(new String(jsonByte));
                        String type = callJson.getString("type");
                        String sdp = callJson.getString("description");
                        createAnswer(sdp);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                }
                break;
            case 0x18:
                //收到answer
                if (content.length > 5) {
                    Log.i(TAG, "收到answer");
                    byte[] from = new byte[16];
                    System.arraycopy(content, 0, from, 0, from.length);
                    fromWho = new String(from);
                    Log.i(TAG, "来自谁" + fromWho);
                    byte[] jsonByte = new byte[content.length - 16];
                    System.arraycopy(content, 16, jsonByte, 0, jsonByte.length);
                    Log.i(TAG, "收到的json" + new String(jsonByte));
                    try {
                        JSONObject callJson = new JSONObject(new String(jsonByte));
                        String type = callJson.getString("type");
                        String sdp = callJson.getString("description");
                        setRemoteDesp(sdp, false);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                }
                break;
            case 0x19:
                if (content.length > 5) {
                    byte[] fromm = new byte[16];
                    System.arraycopy(content, 0, fromm, 0, fromm.length);
                    fromWho = new String(fromm);
                    Log.i(TAG, "来自谁" + fromWho);
                    byte[] jsonBytes = new byte[content.length - 16];
                    System.arraycopy(content, 16, jsonBytes, 0, jsonBytes.length);
                    Log.i(TAG, "收到的json" + new String(jsonBytes));
                    try {
                        JSONObject callJson = new JSONObject(new String(jsonBytes));
                        int label = callJson.getInt("sdpMLineIndex");
                        String id = callJson.getString("sdpMid");
                        String candidate = callJson.getString("sdp");
                        IceCandidate iceCandidate = new IceCandidate(id, label, candidate);
                        addIce(iceCandidate);
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                }
                break;
        }

    }

    private void addIce(IceCandidate iceCandidate) {
        peerConnection.addIceCandidate(iceCandidate);
    }


    private void createAnswer(String sdp) {
        setRemoteDesp(sdp, true);
        peerConnection.createAnswer(new MySdpServer(), videoConstraints);
    }

    private void setRemoteDesp(String sdp, boolean isOffer) {
        if (isOffer) {
            SessionDescription remoteSession = new SessionDescription(SessionDescription.Type.OFFER, sdp);
            peerConnection.setRemoteDescription(new MySdpServer(), remoteSession);
        } else {
            SessionDescription remoteSession = new SessionDescription(SessionDescription.Type.ANSWER, sdp);
            peerConnection.setRemoteDescription(new MySdpServer(), remoteSession);
        }

    }

    public void SHOW(Context context, String s) {
        Toast.makeText(context, s, Toast.LENGTH_SHORT).show();
    }

    private class MySdpServer implements SdpObserver {
        @Override
        public void onCreateSuccess(final SessionDescription sessionDescription) {
            peerConnection.setLocalDescription(new MySdpServer(), sessionDescription);

            if (sessionDescription.type.toString().equals("OFFER")) {
                //提供offer
                String from = fromEdit.getText().toString();
                String to = toEdit.getText().toString();
                sendJson(from, to, sessionDescription, true);
            } else {
                //提供answer
                Log.i("FANG", "创建answer");
                String from = fromEdit.getText().toString();
                String to = fromWho;
                sendJson(from, to, sessionDescription, false);
            }


        }

        @Override
        public void onSetSuccess() {

            Log.i(TAG, "设置sdp成功");

        }

        @Override
        public void onCreateFailure(String s) {
            Log.i(TAG, "创建失败" + s);

        }

        @Override
        public void onSetFailure(String s) {

        }
    }


    private void sendJson(String from, String to, SessionDescription sessionDescription, boolean isCall) {
        try {
            byte[] fromBuffer = new byte[16];
            byte[] toBuffer = new byte[16];
            System.arraycopy(from.getBytes(), 0, fromBuffer, 0, from.length());
            System.arraycopy(to.getBytes(), 0, toBuffer, 0, to.length());
            JSONObject data = new JSONObject();
            data.put("type", sessionDescription.type);
            data.put("description", sessionDescription.description);
            String jsonData = data.toString() + "#";
            Log.i(TAG, jsonData);
            Log.i(TAG, "数据长度" + jsonData.length());
            byte[] content = new byte[jsonData.length() + 33];
            if (isCall) {
                System.arraycopy(messageCode, 1, content, 0, 1);
            } else {
                System.arraycopy(messageCode, 2, content, 0, 1);
            }
            System.arraycopy(toBuffer, 0, content, 1, 16);
            System.arraycopy(fromBuffer, 0, content, 17, 16);
            System.arraycopy(jsonData.getBytes(), 0, content, 33, jsonData.length());
            sendMessage(content);
        } catch (JSONException e) {
            e.printStackTrace();
        }


    }

    private void sendMessage(byte[] content) {
        try {
            outputStream.write(content);
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void onIceGatheringChange(PeerConnection.IceGatheringState iceGatheringState) {

    }

    @Override
    public void onSignalingChange(PeerConnection.SignalingState signalingState) {

    }

    @Override
    public void onIceConnectionChange(PeerConnection.IceConnectionState iceConnectionState) {

    }

    @Override
    public void onIceCandidate(IceCandidate iceCandidate) {
        String from = fromEdit.getText().toString();
        String to = "";
        if (toEdit.getText().length() == 0) {
            to = fromWho;
        } else {
            to = toEdit.getText().toString();
        }
        sendIce(iceCandidate, from, to);
    }


    private void sendIce(IceCandidate candidate, String from, String to) {
        JSONObject json = new JSONObject();
        try {
            json.put("sdpMLineIndex", candidate.sdpMLineIndex);
            json.put("sdpMid", candidate.sdpMid);
            json.put("sdp", candidate.sdp);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        String jsonData = json.toString();
        jsonData = jsonData + "#";
        byte[] fromBuffer = new byte[16];
        byte[] toBuffer = new byte[16];
        System.arraycopy(from.getBytes(), 0, fromBuffer, 0, from.length());
        System.arraycopy(to.getBytes(), 0, toBuffer, 0, to.length());
        byte[] content = new byte[jsonData.length() + 33];
        System.arraycopy(messageCode, 3, content, 0, 1);
        System.arraycopy(toBuffer, 0, content, 1, 16);
        System.arraycopy(fromBuffer, 0, content, 17, 16);
        System.arraycopy(jsonData.getBytes(), 0, content, 33, jsonData.length());
        sendMessage(content);
    }

    @Override
    public void onAddStream(MediaStream mediaStream) {
        VideoTrack remoteVideoTrack = mediaStream.videoTracks.get(0);
        remoteVideoTrack.addRenderer(new VideoRenderer(remoteRender));
    }

    @Override
    public void onRemoveStream(MediaStream mediaStream) {

    }

    @Override
    public void onDataChannel(DataChannel dataChannel) {

    }

    @Override
    public void onRenegotiationNeeded() {

    }

    private void updateVideoView() {


        VideoRendererGui.update(localRender,
                LOCAL_X_CONNECTING, LOCAL_Y_CONNECTING,
                LOCAL_WIDTH_CONNECTING, LOCAL_HEIGHT_CONNECTING, scalingType);

    }

    public static void sendssid(String from) {
        byte mcode[] = {0x11};
        byte[] ssid = from.getBytes();
        byte ssidbuff[] = new byte[16];
        System.arraycopy(ssid, 0, ssidbuff, 0, ssid.length);
        byte[] res = new byte[mcode.length + 17];
        res[17] = '#';
        System.arraycopy(mcode, 0, res, 0, 1);
        System.arraycopy(ssidbuff, 0, res, 1, ssid.length);
        try {
            outputStream.write(res);
            outputStream.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
